#!/usr/bin/python
# -*- coding: utf-8 -*-
#
#	   vlasov.py
#	   
#	   Copyright 2012 Artem Korzhimanov <artem@artem-desktop>
#	   
#	   This program is free software; you can redistribute it and/or modify
#	   it under the terms of the GNU General Public License as published by
#	   the Free Software Foundation; either version 2 of the License, or
#	   (at your option) any later version.
#	   
#	   This program is distributed in the hope that it will be useful,
#	   but WITHOUT ANY WARRANTY; without even the implied warranty of
#	   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	   GNU General Public License for more details.
#	   
#	   You should have received a copy of the GNU General Public License
#	   along with this program; if not, write to the Free Software
#	   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#	   MA 02110-1301, USA.

import sys, time
from PyQt4 import QtGui, QtCore
import mathgl as mgl

class TextForm(QtGui.QTextEdit):
	def __init__(self, parent=None):
		QtGui.QTextEdit.__init__(self, parent)
		
		self.setFontFamily('Monospace')

class Output(object):
	def __init__(self, output):
		self.output = output
		
	def write(self, string):
		if not (string == "\n"):
			self.output.append(string.strip())
			#self.output.append(string)
			
class RunProcess(QtCore.QProcess):
	def __init__(self):
		QtCore.QProcess.__init__(self)
	
	def __del__(self):
		self.close()

class RunThread(QtCore.QThread):
	def __init__(self, filename, widget):
		QtCore.QThread.__init__(self)
		
		self.filename = filename
		self.widget = widget
		
	def printOutput(self):
		self.widget.append(QtCore.QString(self.proc.readAllStandardOutput()).remove('\n'))
	
	def printError(self):
		self.widget.append(QtCore.QString(self.proc.readAllStandardError()).remove('\n'))
		
	def Finalize(self):
		self.printOutput()
		self.printError()
		self.widget.append("Finish")
	
	def run(self):
		self.proc = RunProcess()
		self.proc.readyReadStandardOutput.connect(self.printOutput)
		self.proc.readyReadStandardError.connect(self.printError)
		self.proc.finished.connect(self.Finalize)
		self.proc.start("../bin/vlasov", ["-i", self.filename])
		self.proc.waitForStarted()
		self.proc.waitForFinished()
	
class PlotWidget(QtGui.QLabel):
	def __init__(self, parent=None):
		QtGui.QLabel.__init__(self, parent)
		
		self.img = QtGui.QImage()
		self.pixmap = QtGui.QPixmap()
	
	def setgraph(self, gr):
		self.buffer = '\t'
		self.buffer = self.buffer.expandtabs(3*gr.GetWidth()*gr.GetHeight())
		gr.GetRGB(self.buffer, len(self.buffer))
		
		self.img = QtGui.QImage(self.buffer, gr.GetWidth(), gr.GetHeight(), QtGui.QImage.Format_RGB888)
		self.pixmap = QtGui.QPixmap.fromImage(self.img)
		self.setPixmap(self.pixmap)
		self.update()
	
	def paintEvent(self, event):
		qp = QtGui.QPainter()
		qp.begin(self)
		qp.drawPixmap(0, 0, self.pixmap)
		qp.end()

class ResultsWidget(QtGui.QWidget):
	def __init__(self, parent=None):
		QtGui.QWidget.__init__(self, parent)
		
		self.drawButton = QtGui.QPushButton("Draw")
		self.scriptText = TextForm()
		self.plotArea = PlotWidget()
		
		gr = mgl.mglGraph()
		
		gr.Clf(1, 1, 1)
		gr.SetPlotFactor(1.5)
		
		y = mgl.mglData(100)
		y.Modify("(cos(2*pi*x*10)+1.1)*1000.*rnd-501")
		x = mgl.mglData(100)
		x.Modify("x^2")
		
		gr.SetRange('x', x)
		gr.SetRange('y', y)
		gr.Adjust()
		gr.Axis()
		gr.Box()
		gr.Label("x", "x-Axis", 1)
		gr.Label("y", "y-Axis", 1)
		
		gr.Plot(x, y)
		
		self.vbox = QtGui.QVBoxLayout()
		self.vbox.addWidget(self.drawButton)
		self.vbox.addWidget(self.scriptText)
				
		self.hbox = QtGui.QHBoxLayout()
		self.hbox.addLayout(self.vbox)
		#self.hbox.addStretch(0)
		self.hbox.addWidget(self.plotArea, 1)
		
		self.plotArea.setgraph(gr)
		
		self.setLayout(self.hbox)

class LogWidget(QtGui.QWidget):
	def __init__(self, parent=None):
		QtGui.QWidget.__init__(self, parent)
		
		self.outputForm = TextForm()
		self.outputForm.setReadOnly(True)
		self.outputForm.append("Vlasov solver is executed")
		
		self.output = Output(self.outputForm)
		sys.stdout = self.output
		
		self.vbox = QtGui.QVBoxLayout()
		self.vbox.addWidget(self.outputForm)
		
		self.setLayout(self.vbox)

class TabManager(QtGui.QTabWidget):
	def __init__(self, parent=None):
		QtGui.QTabWidget.__init__(self, parent)
		
		self.res = ResultsWidget()
		self.addTab(self.res, "Results")

		self.log = LogWidget()
		self.addTab(self.log, "Log")

class RunWindow(QtGui.QWidget):
	def __init__(self, filename, parent=None):
		QtGui.QWidget.__init__(self, parent)
		
		self.resize(1200, 800)
		self.setWindowTitle('Vlasov run')
		self.setWindowIcon(QtGui.QIcon('protons-100.png'))
		
		self.tab = TabManager()
		
		layout = QtGui.QHBoxLayout()
		layout.addWidget(self.tab)
		
		self.setLayout(layout)
		
		self.proc = RunThread(filename, self.tab.log.outputForm)
		self.proc.start()

class Layout(QtGui.QWidget):
	def __init__(self, parent=None):
		QtGui.QWidget.__init__(self, parent)
		
		self.filename = None
		
		self.textEdit = TextForm()
		
		self.runButton = QtGui.QPushButton("Run")
		
		self.hbox = QtGui.QHBoxLayout()
		self.hbox.addStretch(1)
		self.hbox.addWidget(self.runButton)
		
		self.vbox = QtGui.QVBoxLayout()
		self.vbox.addWidget(self.textEdit)
		self.vbox.addLayout(self.hbox)
		
		self.setLayout(self.vbox)
	
	@QtCore.pyqtSlot()
	def open(self):
		self.filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File', '.')
		try:
			fname = open(self.filename)
			self.textEdit.setText(fname.read())
			fname.close()
		except:
			pass
			
	@QtCore.pyqtSlot()
	def save(self):
		if self.filename != None:
			f = open(self.filename, 'w')
			f.write(self.textEdit.toPlainText())
			f.close()
		else:
			self.saveas()
	
	@QtCore.pyqtSlot()
	def saveas(self):
		self.filename = QtGui.QFileDialog.getSaveFileName(self, 'Save File', '.')
		try:
			fname = open(self.filename, 'w')
			fname.write(self.textEdit.toPlainText())
			fname.close()
		except:
			pass
	
	@QtCore.pyqtSlot()
	def close(self):
		self.filename = None
		self.textEdit.clear()
	
	@QtCore.pyqtSlot()
	def run(self):
		if self.filename != None:
			self.save()
			self.window = RunWindow(self.filename)
			self.window.show()

class MainWindow(QtGui.QMainWindow):
	def __init__(self):
		QtGui.QMainWindow.__init__(self)
		
		self.resize(640, 480)
		self.setWindowTitle('Vlasov')
		self.setWindowIcon(QtGui.QIcon('protons-100.png'))
		
#-------Set layout------------------------------------------------------
		qb = Layout()
		self.setCentralWidget(qb)

#-------Set actions-----------------------------------------------------
		exit = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/exit.svg'), 'Exit', self)
		exit.setShortcut('Ctrl+Q')
		exit.setStatusTip('Exit application')
		exit.triggered.connect(sys.exit)

		open = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/fileopen.svg'), 'Open file', self)
		open.setShortcut('Ctrl+O')
		open.setStatusTip('Open input file')
		open.triggered.connect(qb.open)
		
		save = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/filesave.svg'), 'Save file', self)
		save.setShortcut('Ctrl+S')
		save.setStatusTip('Save input file')
		save.triggered.connect(qb.save)
		
		saveas = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/filesaveas.svg'), 'Save file as...', self)
		saveas.setShortcut('Ctrl+S')
		saveas.setStatusTip('Save input file as...')
		saveas.triggered.connect(qb.saveas)
		
		close = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/window-close.svg'), 'Close file', self)
		close.setShortcut('Ctrl+W')
		close.setStatusTip('Close input file')
		close.triggered.connect(qb.close)
		
		run = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/system-run.svg'), 'Run program', self)
		run.setShortcut('Ctrl+R')
		run.setStatusTip('Run program')
		run.triggered.connect(qb.run)
		
		stop = QtGui.QAction(QtGui.QIcon('/usr/share/icons/gnome/scalable/actions/stop.svg'), 'Stop program', self)
		stop.setShortcut('Ctrl+R')
		stop.setStatusTip('Stop program')
				
#-------Set status bar--------------------------------------------------
		self.statusBar().showMessage('Ready')
		
#-------Set menubar-----------------------------------------------------		
		menubar = self.menuBar()
		file_menu = menubar.addMenu('&File')
		file_menu.addAction(open)
		file_menu.addAction(save)
		file_menu.addAction(saveas)
		file_menu.addAction(close)
		file_menu.addSeparator()
		file_menu.addAction(exit)
		
		run_menu = menubar.addMenu('&Run')
		run_menu.addAction(run)
		run_menu.addAction(stop)
		
#-------Set toolbar-----------------------------------------------------
		toolbar1 = self.addToolBar('File')
		toolbar1.addAction(open)
		toolbar1.addAction(save)
		toolbar1.addAction(saveas)
		toolbar1.addAction(close)
		
		toolbar2 = self.addToolBar('Run')
		toolbar2.addAction(run)
		toolbar2.addAction(stop)
		
		toolbar3 = self.addToolBar('Exit')
		toolbar3.addAction(exit)
		
def main():
	app = QtGui.QApplication(sys.argv)

	main = MainWindow()
	main.show()
	
	sys.exit(app.exec_())
	
	return 0

if __name__ == '__main__':
	main()
